package com.kilomob.grady.server.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.kilomob.grady.handler.netty.MessageReceiveChannelInitializer;
import com.kilomob.grady.handler.netty.MessageReceiveInitializeTask;
import com.kilomob.grady.server.Server;

/**
 * 
 * netty服务类
 * 
 * @author zhouzhixiang
 * @date 2016年12月31日
 * @since 1.0
 */
public class NettyServer implements Server {
    private static Logger LOGGER = LoggerFactory.getLogger(NettyServer.class);

    private static final Map<String, Object> HANDLER_MAP = new ConcurrentHashMap<String, Object>();
    EventLoopGroup boss = new NioEventLoopGroup(2, new ThreadFactoryBuilder().setNameFormat(
            "Grady-boss-%s").build());
    EventLoopGroup worker = new NioEventLoopGroup(
            Runtime.getRuntime().availableProcessors() * 2 + 1, new ThreadFactoryBuilder()
                    .setNameFormat("Grady-worker-%s").build());
    volatile private static ListeningExecutorService executors;

    /** 序列化协议 **/
    private String protocol = "pt";
    
    /** ID **/
    private String id;

    /** 端口 **/
    private int port;

    /** 是否已启动 **/
    private boolean started = false;

    /** 服务名称 **/
    private String name;
    

    @Override
    public void start() {
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boss, worker);
            bootstrap.channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new MessageReceiveChannelInitializer(protocol, id, HANDLER_MAP));

            bootstrap.bind(new InetSocketAddress("0.0.0.0", port)).sync();
            LOGGER.debug("{} server started successful! the port is:{}", name == null
                    ? "Grady"
                    : name, this.port);
        } catch (Exception e) {
            LOGGER.error("{} server started failed!", name == null ? "Grady" : name, e);
        }
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    @Override
    public void stop() {
        boss.shutdownGracefully();
        worker.shutdownGracefully();
    }

    @Override
    public boolean isStarted() {
        return started;
    }

    /**
     * 业务处理线程
     * 
     * 
     * @param recvTask
     * @param ctx
     * @param response
     */
    public static void submit(MessageReceiveInitializeTask recvTask) {
        if (executors == null) {
            synchronized (NettyServer.class) {
                if (executors == null) {
                    executors = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
                    MoreExecutors.listeningDecorator(executors);
                }
            }
        }
        ListenableFuture<Boolean> listenableFuture = executors.submit(recvTask);

        Futures.addCallback(listenableFuture, new FutureCallback<Boolean>() {
            public void onSuccess(Boolean result) {
                
            }

            public void onFailure(Throwable t) {
                LOGGER.error("handler client request error:", t);
            }
        }, executors);
    }
    

    public static Map<String, Object> getHandlerMap() {
        return HANDLER_MAP;
    }

    public String getProtocol() {
        return protocol;
    }


    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
    
}
